using System;
using System.Collections.Generic;
using System.Linq;
using GorillaEngine.ICore;

namespace GorillaEngine.Core.Components{
    public class Randomizer : IRandomizer{

        private Random _random;
        private readonly List<int> _nonReoccuringInts;

        public Randomizer(int seed){
            _random = new Random(seed);
            _nonReoccuringInts = new List<int>();
        }

        public virtual void InitializeNew(int seed){
            _random = new Random(seed);
            _nonReoccuringInts.Clear();
        }
        public virtual void ClearNonReoccuringInts(){
            _nonReoccuringInts.Clear();
        }

        public virtual int RandomInt(){
            return _random.Next();
        }
        public virtual int RandomInt(int to){
            return _random.Next(to);
        }
        public virtual int RandomInt(int from, int to){
            return _random.Next(@from, to);
        }

        public virtual float RandomFloat(int decimalPlace = 1){
            var decimals = GetDecimalPlace(decimalPlace);
            return (float)decimals*_random.Next();
        }
        public virtual float RandomFloat(int max, int decimalPlace = 1){
            return RandomFloat(0, max, decimalPlace);
        }
        public virtual float RandomFloat(int from, int to, int decimalPlace = 1){
            var decimals = GetDecimalPlace(decimalPlace);
            return _random.Next(@from, to)*(float) (decimals);
        }

        public virtual double RandomDouble(int decimalPlace = 1){
            var decimals = GetDecimalPlace(decimalPlace);
            return decimals*_random.Next();
        }
        public virtual double RandomDouble(int max, int decimalPlace = 1){
            return RandomDouble(0, 1, decimalPlace);
        }
        public virtual double RandomDouble(int from, int to, int decimalPlace = 1){
            var decimals = GetDecimalPlace(decimalPlace);
            return _random.Next(from, to)*(decimals);
        }

        public virtual int GetNonReocurringInt(){
            var toReturn = _random.Next();

            while (_nonReoccuringInts.Contains(toReturn)){
                toReturn = _random.Next();
            }

            _nonReoccuringInts.Add(toReturn);
            return toReturn;
        }
        public virtual int? GetNonReocurringInt(int max){
            return GetNonReocurringInt(0, max);
        }
        public virtual int? GetNonReocurringInt(int from, int to){
            var range = DetermineRange(from,to);

            var toReturn = _random.Next(from, to);
            while (_nonReoccuringInts.Contains(toReturn)){
                if (range.All(x => _nonReoccuringInts.Contains(x)))
                    return null;

                toReturn = _random.Next(from, to);
            }

            _nonReoccuringInts.Add(toReturn);
            return toReturn;
        }

        private double GetDecimalPlace(int decimalPlace){
            double toReturn = _random.NextDouble();
            for (var dec = 1; dec < decimalPlace; dec++){
                toReturn *= _random.NextDouble();
            }
            return toReturn;
        }
        private IEnumerable<int> DetermineRange(int from, int to){
            var toReturn = new List<int>();

            for (var i = from; i < to; i++){
                toReturn.Add(i);
            }
            return toReturn;
        }
    }
}